
import os
import sys
import configparser
import click
import shutil
from pathlib import Path
import shlex

# 常量定义
CONFIG_FILE = "config.ini"
SECTION_NAME = "Work"
BLACKLIST_DELETE = ['workdir', 'default', 'user']
EXTRACT_CMD_MIN_ARGS = 5  # extract <type> from <source> to <dest>

# 全局变量
config = configparser.ConfigParser()
workdir = ""

def init_config():
    """初始化配置文件"""
    try:
        if not config.read(CONFIG_FILE):
            click.secho(f"[!] 配置文件 {CONFIG_FILE} 不存在，将使用默认设置", fg="yellow")
            config.add_section(SECTION_NAME)
        
        if not config.has_option(SECTION_NAME, "workdir"):
            click.secho(f"[!] 未找到 workdir 配置，使用当前目录", fg="yellow")
            config.set(SECTION_NAME, "workdir", os.getcwd())
        
        global workdir
        workdir = config.get(SECTION_NAME, "workdir")
        if not os.path.exists(workdir):
            os.makedirs(workdir)
            click.secho(f"[+] 创建工作目录: {workdir}", fg="green")
            
    except configparser.NoSectionError:
        click.secho(f"[!] 配置文件格式错误，缺少 [{SECTION_NAME}] 节", fg="red")
        sys.exit(1)
    except Exception as e:
        click.secho(f"[!] 配置初始化失败: {str(e)}", fg="red")
        sys.exit(1)

def validate_path(path, is_directory=False):
    """验证路径是否安全（在workdir范围内）"""
    real_path = os.path.realpath(path)
    workdir_real = os.path.realpath(workdir)
    
    if not real_path.startswith(workdir_real):
        click.secho(f"[!] 路径 {path} 超出工作目录范围", fg="red")
        return False
        
    if is_directory and not os.path.isdir(real_path):
        click.secho(f"[!] 目录 {path} 不存在", fg="red")
        return False
        
    return True

# ------------------------------
# 命令处理函数
# ------------------------------
def handle_config_set(args):
    """处理 config set 命令"""
    if len(args) < 2:
        click.secho("[!] 用法: config set <key> <value>", fg="red")
        return
        
    key, value = args[0], args[1]
    try:
        config.set(SECTION_NAME, key, value)
        with open(CONFIG_FILE, 'w') as f:
            config.write(f)
        click.secho(f"[+] 已设置 {key} = {value}", fg="green")
        
        # 如果修改了workdir，立即更新
        if key == "workdir":
            global workdir
            workdir = value
            if not os.path.exists(workdir):
                os.makedirs(workdir)
                click.secho(f"[+] 创建新工作目录: {workdir}", fg="green")
    except Exception as e:
        click.secho(f"[!] 设置配置失败: {str(e)}", fg="red")

def handle_config_del(args):
    """处理 config del 命令"""
    if len(args) < 1:
        click.secho("[!] 用法: config del <key>", fg="red")
        return
        
    key = args[0]
    if key in BLACKLIST_DELETE:
        click.secho(f"[!] 禁止删除系统配置项: {key}", fg="red")
        return
        
    try:
        if config.has_option(SECTION_NAME, key):
            config.remove_option(SECTION_NAME, key)
            with open(CONFIG_FILE, 'w') as f:
                config.write(f)
            click.secho(f"[+] 已删除配置项: {key}", fg="green")
        else:
            click.secho(f"[!] 配置项 {key} 不存在", fg="red")
    except Exception as e:
        click.secho(f"[!] 删除配置失败: {str(e)}", fg="red")

def handle_flush(args):
    """处理 flush 命令（重新加载配置）"""
    try:
        config.read(CONFIG_FILE)
        global workdir
        old_workdir = workdir
        workdir = config.get(SECTION_NAME, "workdir", fallback=workdir)
        
        if old_workdir != workdir:
            if not os.path.exists(workdir):
                os.makedirs(workdir)
                click.secho(f"[+] 创建新工作目录: {workdir}", fg="green")
            else:
                click.secho(f"[+] 工作目录已更新为: {workdir}", fg="green")
        click.secho("[+] 配置已刷新", fg="green")
    except Exception as e:
        click.secho(f"[!] 刷新配置失败: {str(e)}", fg="red")

def handle_get_config(args):
    """处理 get config 命令"""
    if len(args) < 1:
        click.secho("[!] 用法: get config <key>", fg="red")
        return
        
    key = args[0]
    try:
        value = config.get(SECTION_NAME, key)
        click.secho(f"{value}", fg="green")
    except configparser.NoOptionError:
        click.secho(f"[!] 配置项 {key} 不存在", fg="red")
    except Exception as e:
        click.secho(f"[!] 获取配置失败: {str(e)}", fg="red")

def handle_list_entities(args):
    """处理 @entity 命令（列出实体）"""
    if len(args) < 1:
        click.secho("[!] 用法: get @entity.<type>", fg="red")
        return
        
    entity_type = args[0]
    try:
        if not os.path.isdir(workdir):
            click.secho(f"[!] 工作目录 {workdir} 不存在", fg="red")
            return
            
        count = 0
        for entry in os.listdir(workdir):
            entry_path = os.path.join(workdir, entry)
            if os.path.isdir(entry_path):
                if entity_type in ["@entity.dir", "@entity.all"]:
                    click.secho(f"{entry} @entity.dir", fg="blue")
                    count += 1
            else:
                suffix = Path(entry).suffix.replace('.', '')
                file_entity = f"@entity.file.{suffix}" if suffix else "@entity.file"
                if (entity_type in ["@entity.file.all", "@entity.all"] or 
                    entity_type == file_entity):
                    click.secho(f"{entry} {file_entity}")
                    count += 1
                    
        if count == 0:
            click.secho(f"[W] 未找到匹配的实体类型: {entity_type}", fg="yellow")
    except Exception as e:
        click.secho(f"[!] 列出实体失败: {str(e)}", fg="red")

def handle_extract(args):
    """处理 extract 命令"""
    if len(args) < 5 or args[1] != "from" or args[3] != "to":
        click.secho("[!] 用法: extract <entity_type> from <source_dir> to <dest_dir>", fg="red")
        return
        
    entity_type, _, source_dir, _, dest_dir = args[0], args[1], args[2], args[3], args[4]
    source_path = os.path.join(workdir, source_dir)
    dest_path = os.path.join(workdir, dest_dir)
    
    if not validate_path(source_path, is_directory=True):
        return
        
    if not os.path.exists(dest_path):
        os.makedirs(dest_path)
        click.secho(f"[+] 创建目标目录: {dest_path}", fg="green")
    
    count = 0
    try:
        for entry in os.listdir(source_path):
            entry_fullpath = os.path.join(source_path, entry)
            entry_path = Path(entry_fullpath)
            
            # 确定实体类型
            current_entity = "@entity.dir" if entry_path.is_dir() else \
                            f"@entity.file.{entry_path.suffix.replace('.', '')}" if entry_path.suffix else "@entity.file"
            
            if current_entity == entity_type or entity_type == "@entity.all":
                dest_fullpath = os.path.join(dest_path, entry)
                
                try:
                    if entry_path.is_dir():
                        shutil.copytree(entry_fullpath, dest_fullpath, dirs_exist_ok=True)
                        shutil.rmtree(entry_fullpath)
                        click.secho(f"[+] 移动目录: {entry}", fg="green")
                    else:
                        shutil.move(entry_fullpath, dest_fullpath)
                        click.secho(f"[+] 移动文件: {entry}", fg="green")
                    count += 1
                except Exception as e:
                    click.secho(f"[!] 处理 {entry} 失败: {str(e)}", fg="red")
        
        if count > 0:
            click.secho(f"[+] 成功处理 {count} 个项目", fg="green")
        else:
            click.secho("[W] 未找到匹配的项目", fg="yellow")
            
    except Exception as e:
        click.secho(f"[!] 提取操作失败: {str(e)}", fg="red")


def handle_unknown_command(args):
    """处理未知命令"""
    click.secho(f"[!] 未知命令", fg="red")


# 命令映射字典
COMMAND_HANDLERS = {
    "config set": handle_config_set,
    "config del": handle_config_del,
    "flush": handle_flush,
    "get config": handle_get_config,
    "get @entity": handle_list_entities,
    "extract": handle_extract
}

def dispatch_command(userinput):
    """解析并分发命令"""
    try:
        # 使用shlex处理带引号的参数
        parts = shlex.split(userinput.strip())
        if not parts:
            return
            
        # 处理多词命令
        cmd_key = parts[0]
        args = parts[1:]
        
        # 检查是否为双词命令
        if len(parts) >= 2 and f"{parts[0]} {parts[1]}" in COMMAND_HANDLERS:
            cmd_key = f"{parts[0]} {parts[1]}"
            args = parts[2:]
        # 检查是否为get @entity命令
        elif parts[0] == "get" and len(parts) >= 2 and parts[1].startswith("@entity"):
            cmd_key = "get @entity"
            args = parts[1:]
            
        # 执行命令
        handler = COMMAND_HANDLERS.get(cmd_key, handle_unknown_command)
        handler(args)
        
    except Exception as e:
        click.secho(f"[!] 命令处理错误: {str(e)}", fg="red")

def main():
    """主函数"""
    init_config()
    click.secho("输入命令 (help 查看帮助) >>", fg="cyan")
    
    while True:
        try:
            userinput = input(f"{workdir}>> ")
            if userinput.strip().lower() in ["exit", "quit"]:
                click.secho("[+] 工具已退出", fg="green")
                sys.exit(0)
            dispatch_command(userinput)
        except KeyboardInterrupt:
            click.secho("\n[!] 输入已取消，输入exit退出", fg="yellow")
        except Exception as e:
            click.secho(f"[!] 发生错误: {str(e)}", fg="red")

if __name__ == "__main__":
    main()